#ifndef __CZF_GRID_CTRL_H__
#define __CZF_GRID_CTRL_H__

#include <vector>
#include "SimpleWnd.h"

#define VIEWER_STATUS_NORMAL 0
#define VIEWER_STATUS_READY_SIZE 1
#define VIEWER_STATUS_SIZING 2

#define VIEWER_TEXT_LEFT 0
#define VIEWER_TEXT_CENTER 1
#define VIEWER_TEXT_RIGHT 2

using namespace std;
typedef vector<TCHAR*> VectorStr;

#define GDM_FIRST          (WM_USER+500)
#define GDM_ENTER_CELL     GDM_FIRST
// wParam is the child id.
// lParam: HIWORD(lParam) is row. LOWORD(lParam) is col.
#define GDM_DBL_CLICK      (GDM_FIRST + 1)
// wParam is the child id.
// lParam: HIWORD(lParam) is row. LOWORD(lParam) is col.
#define GDM_ENTER_PRESSED  (GDM_FIRST + 2)
// wParam is the child id.
// lParam: HIWORD(lParam) is CurRow. LOWORD(lParam) is CurCol.
#define GDM_START_EDITING  (GDM_FIRST + 3)
// wParam is the child id.
// lParam: HIWORD(lParam) is row. LOWORD(lParam) is col.
#define GDM_END_EDITING    (GDM_FIRST + 4)
// LOWORD(wParam) is the child id.
// HIWORD(wParam) is end code:
//                END_WITH_CANCEL    0
//                END_WITH_LEAVING   1
//                END_WITH_RETURNKEY 2
// lParam is the pointer to the result string.

#define WM_ENDEDIT WM_USER + 500
#define END_WITH_CANCEL    0
#define END_WITH_LEAVING   1
#define END_WITH_RETURNKEY 2

// sent to parent when editing has terminated
// WPARAM  = code: END_WITH_RETURNKEY - when the user has pressed VK_RETURN 
//                 END_WITH_LEAVING - when edit loosing focus.  
//						 END_WITH_CANCEL - when ESC was pressed
// LPARAM = pointer to LPTSTR of the edit

// represents inplace editor which can be used as a child window
class CInplaceEdit : public CWnd
{
public:
	CInplaceEdit();
   void SetParent(HWND hParent);
	BOOL StartEditing(LPRECT rcCoords, UINT uID, LPCTSTR szInitialText, HFONT hFont = NULL);

protected:
	HWND m_hParent;

	BEGIN_MSG_MAP(CInplaceEdit)
		MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
		MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
	END_MSG_MAP()

	LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

	void StopEditing(WPARAM wCode);
private:
	BOOL m_bStopped;
};

class CInplaceDroplist : public CWnd
{
public:
	CInplaceDroplist();
   void SetParent(HWND hParent);
   /*
    * rcCoords is the RECT for this Combo.
    * pSzItems are the strings for the items to be selected, the last one is NULL.
    * nIdx is the 
    */
	BOOL StartSelecting(LPRECT rcCoords, UINT uID, LPCTSTR szInitText, LPCTSTR* pszItems,
						HFONT hFont = NULL);
protected:
	HWND m_hParent;

	BEGIN_MSG_MAP(CInplaceDroplist)
		MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
		MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
		MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
	END_MSG_MAP()

	LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

	void StopSelecting(WPARAM wCode);
private:
	BOOL m_bStopped;
};

class CGridCtrl : public CWnd
{
public:
	CGridCtrl();
	virtual ~CGridCtrl();

	DECLARE_WND_CLASS_EX (_T("CZFGridWnd"), DEFAULT_CLASS_STYLE, COLOR_WINDOW)

	BEGIN_MSG_MAP(CGridCtrl)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
		MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
		MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnMouseEvents)
		MESSAGE_HANDLER(WM_LBUTTONDOWN, OnMouseEvents)
		MESSAGE_HANDLER(WM_LBUTTONUP, OnMouseEvents)
		MESSAGE_HANDLER(WM_RBUTTONDOWN, OnMouseEvents)
		MESSAGE_HANDLER(WM_RBUTTONUP, OnMouseEvents)
		MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseEvents)
		MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
		MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
		MESSAGE_HANDLER(WM_HSCROLL, OnScroll)
		MESSAGE_HANDLER(WM_VSCROLL, OnScroll)
      MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
      MESSAGE_HANDLER(WM_SIZE, OnSize)
      MESSAGE_HANDLER(WM_ENDEDIT, OnEndEdit)
      MESSAGE_HANDLER(WM_ENABLE, OnEnable)
	END_MSG_MAP()

protected:
	LRESULT OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnGetDlgCode(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnMouseEvents(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnFocus(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
   LRESULT OnEnable(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnSetFont(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
   LRESULT OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
   LRESULT OnEndEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

	void Point2Cell(POINT& pt);
	void DrawCells(HDC hDC, RECT& rcCells);
	void DrawHeader(HDC hDC, int l, int r);
	void DrawSizingLine(int x, int y0, int y1);
   int GetRowHeight();
   void SetScrollBars();
   int GetTotalWidth();
   void DrawFocus(HDC hDC, RECT* prc);
   void SelectCell(const POINT& cell);
   void SetCellVisible(const POINT& cell);
   void GetCellRect(const POINT* cell, RECT* rc);
   void GetRowRect(int nRow, RECT* rc);
   LRESULT OnVKLeft();
   LRESULT OnVKRight();
   LRESULT OnVKUp();
   LRESULT OnVKDown();
   LRESULT OnVKNext();
   LRESULT OnVKPrior();

   HBRUSH                     m_hbrHdrBk;
	HBRUSH                     m_hbrNormal;
	COLORREF                   m_clrLine;
	HPEN                       m_penLine;
	COLORREF                   m_clrText;
   COLORREF                   m_clrDisabledText;
	COLORREF                   m_clrBrightLine;
	HPEN                       m_penBright;
	COLORREF                   m_clrDarkLine;
	HPEN                       m_penDark;
	COLORREF                   m_clrHilitText;
	HBRUSH                     m_hbrHilit;

	HWND                       m_hParent;
	RECT                       m_rcSize;
	int                        m_nCols;
	int                        m_nRowHeight;
	int*                       m_pColWidth;
	int*                       m_pColPos;
	UINT*                      m_pColAlign;
	VectorStr                  m_vecString;
	int                        m_nRows;
	int                        m_nHOffset;
	int                        m_nFirstRow;
	BOOL                       m_bResize;
	int                        m_nCurRow;
	int                        m_nPrevRow;
   int                        m_nCurCol;
   int                        m_nPrevCol;
	int                        m_nStatus;
	int                        m_nPrevSizingLine;
	int                        m_nSizedCol;
	int                        m_nSizeLeftLimit;
   bool                       m_bHScrolled;
   bool                       m_bVScrolled;
   bool                       m_bEnabled;
   UINT                       m_nID;
   CInplaceEdit               m_edit;
   CInplaceDroplist           m_droplist;

public:
   HWND CreateGridCtrl (HWND hParent, RECT& rc, DWORD style, DWORD stylex, UINT nID);
   int SetCols(int cols);
	int GetRows();
	int GetCols();
	void InsertRows(int nStart, int nCount);
	void DeleteRows(int nStart, int nCount);
	void SetString(int nRow, int nCol, LPCTSTR szText);
   LPCTSTR GetString(int nRow, int nCol);
	void SetCurCellString(LPCTSTR szText);
   LPCTSTR GetCurCellString();
	void SetRowHeight(int nHeight);
	void SetColWidth(int nCol, int nWidth);
	void SetResize(BOOL bResize);
	void SetColAlign(UINT* puAlign, int nCol0, int nCount);
   void EditCurCell();
   void DroplistCurCell(LPCTSTR* pszItems);
   void SetCurCell(int nRow, int nCol);
   void GetCurCell(int* pnRow, int *pnCol);
};

#endif